package backend;
import java.util.Vector;
import java.util.HashMap;

/**
 * This class represents a role in general hierachical RBAC (2a). A role is
 * defined as a collection of permissions that a user can have corresponding to
 * some defined role in an organization. 
 * 
 * @author Aaron A. Lovato
 */

public class Role
{
    // The name of this role
    private String name;
    
    // All permissions defined for this role
    private HashMap<String, Permission> permissions;
    
    // The users assigned to this role
    private HashMap<String, User> users;
    
    // Any subroles this role is a superset of
    private Vector<Role> subroles;
    
    // This role's parents
    private Vector<Role> parents;
    
    // LAME HACK ALERT!!! Keep track of server
    private Server server;
    
    
    /**
     * Create a new Role. The role must be assigned a name upon creation.
     *
     * @param name This role's name.
     * @param server Server this role is associated with
     */
    public Role(String name, Server server)
    {
        this.name = name;
        this.server = server;
        this.permissions = new HashMap<String, Permission>();
        this.users = new HashMap<String, User>();
        this.subroles = new Vector<Role>();
        this.parents = new Vector<Role>();
    }
    
    /**
     * Gets this role's server.
     *
     * @return This role's server.
     */
    public Server getServer()
    {
        return server;
    }
    
    /**
     * Gets the parent roles.
     * @return This role's parents.
     */
    public Vector<Role> getParents()
    {
        return this.parents;
    }
    
    /**
     * Adds a parent role.
     * @param parent New parent role.
     */
    public void addParent(Role parent)
    {
        this.parents.add(parent);
    }

    /**
     * Removes a parent role
     * @param parent New parent role.
     */
    public void removeParent(Role parent)
    {
        this.parents.remove(parent);
    }


    /**
     * Gets this role's name.
     *
     * @return This role's name.
     */
    public String getName()
    {
        return name;
    }
    
    /**
     * Sets this role's name.
     *
     * @param name This role's new name.
     */
    public void setName(String name)
    {
        this.name = name;
    }
    
    /**
     * Assign a user to this role.
     *
     * @param user User to assign to this role.
     */
    public void addUser(User user) throws Exception
    {
        if(this.users.containsKey(user.getName()))
        {
            throw new 
            Exception("This role already contains this user name");
        }
        this.users.put(user.getName(), user);
    }
     
    /**
     * Remove a user from this role.
     *
     * @param user User to remove from this role
     */
    public void removeUser(User user)
    {
        System.out.println(this.users.remove(user.getName()));
    }
    
    /**
     * Gets a Vector containing all of the users assigned to this role.
     * 
     * @return All of the users assigned to this role.
     */
    public HashMap<String, User> getUsers()
    {
        return new HashMap<String, User>(this.users);
    }
    
    
    /**
     * Assign a permission to this role.
     *
     * @param permission Permission to add.
     */
    public void addPermission(Permission permission) throws Exception
    {
        if (this.permissions.containsKey(permission.getName()))
        {
            throw new 
            Exception("This role already contains this permission name");
        }
        
        permissions.put(permission.getName(), permission);
    }
    
    
    /**
    * Assign a permission to this role.
    *
    * @param name Name of the permission to be added
    * @param value Value to assign to this permission
    */
    public void addPermission(String name, String value) throws Exception
    {
        if (this.permissions.containsKey(name))
        {
            throw new 
            Exception("This role already contains this permission name");
        }
            
        Permission p = new Permission(name, value);
        permissions.put(name, p);
    }
    
    /**
     * Set a permission for this role.
     *
     * @param name Name of the permission to be changed
     * @param value Value to assign to this permission
     */
    public void setPermission(String name, String value) throws Exception
    {
        if (!this.permissions.containsKey(name))
        {
            throw new 
            Exception("This role does not contain this permission name: " + name);
        }
        
        permissions.get(name).setValue(value);
    }
    
    /**
    * Remove a Permission from this role.
    *
    * @param name Name of the permission to remove from this role
    */
    public void removePermission(String name) throws Exception
    {
        if (!this.permissions.containsKey(name))
        {
            throw new Exception("This permission does not exist in this role");
        }
        
        this.permissions.remove(name);
    }
    
    /**
    * Gets a HashMap containing all of the permissions assigned to this role.
    * 
    * @return All of the permissions assigned to this role.
    */
    public HashMap<String, Permission> getPermissions()
    {
        return new HashMap<String, Permission>(this.permissions);
    }
    
    /**
     * Add a subrole to this role.
     *
     * @param role Role that is a subrole of this role.
     */
    public void addSubRole(Role role)
    {
        role.addParent(this);
        this.subroles.add(role);
    }
    
    /**
     * Remove a subrole from this role.
     * 
     * @param role Role to be removed as a subrole of this role.
     */
    public void removeSubRole(Role role)
    {
        this.subroles.remove(role);
    }
    
    /**
     * Get a Vector containing all subroles of this role.
     * 
     * @return All of the subroles of this role.
     */
    public Vector<Role> getSubRoles()
    {
        return new Vector<Role>(this.subroles);
    }

    /**
     * Print out a Role in a pretty string for testing.
     * @return A string representing a Role.
     */
    public String toString()
    {
        return this.name;
    }
}
